/******************************************************************
 * linklist.h
 * this file defines all of the interfaces used to operate linklist
 *****************************************************************/

#ifndef	_LINKLIST_H_INCLUDED
#define	_LINKLIST_H_INCLUDED

#include <semaphore.h>

typedef struct lnode_s
{//linklist's node
	void			*dataptr;
	size_t			DataSize;
	struct lnode_s	*prior;			//first结点的此域为NULL
	struct lnode_s	*next;			//last结点此域为NULL
}lnode_t;

typedef struct llist_s
{//head
	unsigned int	total_num;		//结点数目
	unsigned int	rd_counter;		//读者数目(故此为读者优先)
	struct lnode_s	*first;			//first node
	struct lnode_s	*last;			//last node
	sem_t			mutex;			//to lock rd_counter
	sem_t			wr_sem;			//write lock
}llist_t;

llist_t		*lklst_init();
	//create a header node, and return a pointer point to it;
	//ON FAIL:		RETURN NULL;
	//after this:	total_num	= 0;
	//				rd_counter	= 0;
	//				first		= NULL;
	//				last		= NULL;
	//				mutex		= 1;
	//				wr_sem		= 1;

llist_t		*lklst_destroy(llist_t *head);
	//destroy all the memory owned by this list,,但不会删除head,为避免another
	//thread 对其访问造成的segment fault
	//<从最后一个结点删起,可以避免出错时链表中断造成内存泄漏>
	//*NOTICE* 如果通过Insert动作加入的结点是从堆上分配,则user应该自己去free掉
	//ON RETURN:	SUCC: head
	//				FAIL: NULL

lnode_t		*lklst_insert(llist_t *head, void *to_insert, const size_t datasize);
	//insert a new node to the beginning of the list;
	//ON RETURN:	SUCCESS, return its addr;
	//				FAIL:		return NULL;

llist_t		*lklst_delete(llist_t *head, void *to_del, int (*fcmp)(void *data1, void *data2));
	//delete the node whose data is EQUAL to *to_del, ACCORDING TO function fcmp()
	//because this func doesn't know how to determine the EQUAL condition, and
	//user may have another mind on how to determine it :)
	//***NOTICE*** 相应单元free掉之后,不要尝试再访问之
	//比如:当结点data为student时,可以通过不同的 fcmp 来匹配学号,or匹配姓名, or..等等
	//ON RETURN:
	//			SUCCESS: head	[因为返回被del的后一个节点或者前一个节点都不合适(考虑del的是last或者first时)]
	//			FAIL:	NULL, usually this means no match in the list

llist_t		*lklst_delete_all(llist_t *head, void *to_del, int (*fcmp)(void *data1, void *data2));
	//将所有匹配的结点都从链表中删除
	//ON	RETURN: 和lklst_delete()返回值代表意义一致

void		*lklst_get_content(llist_t *head, lnode_t *node_addr, void *content);
	//仅给定的结点地址存在的情况下,返回data域
	//在其他任何情况都会返回NULL
	
lnode_t		*lklst_query(llist_t *head, lnode_t *start, void *to_query, int (*fcmp)(void *data1, void *data2));
	//walk through the list and find the FIRST node matching giving data
	//if start was given(NOT NULL), shall check if that's in the list first, and query
	//start from it, if it is really in it; if it's not in the list,仍然从head开始查找(用来解决两次查询之间此结点被其他线程del的bug)
	//So if it's NULL, will still  query start from the head 
	//如此的接口设计是为方便通过多次调用,找出所有的匹配结点,
	//当要从第一个node开始找时,给出 head ,所以,当给出的 start
	//是第N个结点时,会从 N->next 开始找,
	//以避免一些问题,比如多次调用查找结果为同一个结点,或者给出最后一个结点->next造成的段错误
	//ON RETURN:	SUCC: 此次查询中第一个匹配的结点地址
	//				FAIL: NULL (可以说明没有匹配的结果,或 start 不存在)



#endif	//_LINKLIST_H_INCLUDED
